﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Auth;
using Microsoft.WindowsAzure.Storage.Table;


namespace Project.Library
{

    public class TableStorage : IData
    {

        private CloudStorageAccount storageAccount;

        public int Init(String ConnectionString)
        {
            try
            {
                storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting(ConnectionString));
                return 1;
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public int Create<T>(String TableName, ref T oClass) where T : TableEntity, new()
        {

            try
            {
                // Create the table client.
                CloudTableClient tableClient = storageAccount.CreateCloudTableClient();

                // Create the table if it doesn't exist.
                CloudTable table = tableClient.GetTableReference(TableName);
                table.CreateIfNotExists();

                // Retrive a single Entity
                TableOperation oTableOperation = TableOperation.Retrieve<T>(oClass.PartitionKey, oClass.RowKey);
                TableResult oTableResult = table.Execute(oTableOperation);

                //Assign Retrived Result to a Student Object
                T oResult = (T)oTableResult.Result;

                //Update if not null
                if (oResult != null)
                {
                    return 2;
                }

                TableOperation insertOperation = TableOperation.Insert(oClass);
                table.Execute(insertOperation);
                return 1;


            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public List<T> Read<T>(String TableName,String PartitionKey, String RowKey) where T : TableEntity, new()
        {

            try
            {

                // Create the table client.
                CloudTableClient tableClient = storageAccount.CreateCloudTableClient();

                // Create the table if it doesn't exist.
                CloudTable table = tableClient.GetTableReference(TableName);

                if (!table.Exists())
                {
                    return null;
                }


                TableQuery<T> query = new TableQuery<T>().Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, PartitionKey));



                return (List<T>)table.ExecuteQuery(query).ToList();
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public int Update<T>(String TableName, ref T oClass) where T:TableEntity
        {
            try
            {
                // Create the table client.
                CloudTableClient tableClient = storageAccount.CreateCloudTableClient();

                // Create the table if it doesn't exist.
                CloudTable table = tableClient.GetTableReference(TableName);

                if (!table.Exists())
                {
                    return 0;
                }

                // Retrive a single Entity
                TableOperation oTableOperation = TableOperation.Retrieve<T>(oClass.PartitionKey, oClass.RowKey);
                TableResult oTableResult = table.Execute(oTableOperation);

                //Assign Retrived Result to a Student Object
                T oResult = (T)oTableResult.Result;

                //Update if not null
                if (oResult != null)
                {
                    oClass.PartitionKey = oResult.PartitionKey;
                    oClass.RowKey = oResult.RowKey;

                    // Update Using Replace Table Operation 
                    TableOperation updateOperation = TableOperation.Replace(oClass);
                    table.Execute(updateOperation);

                    //OR

                    // Create the InsertOrReplace TableOperation to do an insert if the entity doesnot exist
                    TableOperation insertOrReplaceOperation = TableOperation.InsertOrReplace(oClass);
                    table.Execute(insertOrReplaceOperation);

                    return 1;
                }

            }
            catch (Exception e)
            {
                throw e;
            }

            return 0;
        }

        public int Delete(String TableName)
        {
            try
            {
                // Create the table client.
                CloudTableClient tableClient = storageAccount.CreateCloudTableClient();

                // Create the table if it doesn't exist.
                CloudTable table = tableClient.GetTableReference(TableName);

                if (!table.Exists())
                {
                    return 0;
                }

                    table.DeleteIfExists();
                    return 1;

            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public int Delete<T>(String TableName, String PartitionKey, String RowKey) where T : TableEntity
        {
            try
            {
                // Create the table client.
                CloudTableClient tableClient = storageAccount.CreateCloudTableClient();

                // Create the table if it doesn't exist.
                CloudTable table = tableClient.GetTableReference(TableName);

                if (!table.Exists())
                {
                    return 0;
                }

                if ((PartitionKey == "" ) && (RowKey == ""))
                {
                    table.DeleteIfExists();
                    return 1;
                }

                // Retrive a single Entity
                TableOperation oTableOperation = TableOperation.Retrieve<T>(PartitionKey, RowKey);
                TableResult oTableResult = table.Execute(oTableOperation);

                //Assign Retrived Result to a Student Object
                T oResult = (T)oTableResult.Result;

                //Delete if not null
                if (oResult != null)
                {

                    // Perform Delete Opration
                    TableOperation deleteOperation = TableOperation.Delete(oResult);
                    table.Execute(deleteOperation);
                }
            }
            catch (Exception e)
            {
                throw e;
            }

            return 0;
        }

    }
}
